added Feb 2001 SDK
[windows-sources.git] / shared source / sscli20 / samples / compilers / myc / src / exe.cs
blob3358314f45999ed51e645759846f08ff65e6f4cc
1 //------------------------------------------------------------------------------
2 // <copyright file="exe.cs" company="Microsoft">
3 //
4 // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
5 //
6 // The use and distribution terms for this software are contained in the file
7 // named license.txt, which can be found in the root of this distribution.
8 // By using this software in any fashion, you are agreeing to be bound by the
9 // terms of this license.
10 //
11 // You must not remove this notice, or any other, from this software.
12 //
13 // </copyright>
14 //------------------------------------------------------------------------------
16 namespace MyC
18 using System;
19 using System.Reflection.Emit;
20 using System.Reflection;
21 using System.Collections;
23 public class Exe
25 AppDomain appdomain; // assembly domain
26 AssemblyName appname; // assembly name
27 AssemblyBuilder appbuild; // assembly builder
28 ModuleBuilder emodule; // module builder
29 TypeBuilder eclass; // current class
30 MethodBuilder emethod; // current method
31 String filename;
32 String classname;
33 Hashtable opcodehash;
34 ILGenerator il;
35 System.Diagnostics.SymbolStore.ISymbolDocumentWriter srcdoc; // debug source file
36 bool localsdone = false; // track if we are now emitting instructions
38 public void initOpcodeHash()
40 opcodehash = new Hashtable(32); // default initial size
41 opcodehash["neg"] = OpCodes.Neg;
42 opcodehash["mul"] = OpCodes.Mul;
43 opcodehash["div"] = OpCodes.Div;
44 opcodehash["add"] = OpCodes.Add;
45 opcodehash["sub"] = OpCodes.Sub;
46 opcodehash["not"] = OpCodes.Not;
47 opcodehash["and"] = OpCodes.And;
48 opcodehash["or"] = OpCodes.Or;
49 opcodehash["xor"] = OpCodes.Xor;
50 opcodehash["pop"] = OpCodes.Pop;
52 opcodehash["br"] = OpCodes.Br;
53 opcodehash["beq"] = OpCodes.Beq;
54 opcodehash["bge"] = OpCodes.Bge;
55 opcodehash["ble"] = OpCodes.Ble;
56 opcodehash["blt"] = OpCodes.Blt;
57 opcodehash["bgt"] = OpCodes.Bgt;
58 opcodehash["brtrue"] = OpCodes.Brtrue;
59 opcodehash["brfalse"] = OpCodes.Brfalse;
61 opcodehash["cgt"] = OpCodes.Cgt;
62 opcodehash["clt"] = OpCodes.Clt;
63 opcodehash["ceq"] = OpCodes.Ceq;
65 opcodehash["ldc.i4.-1"] = OpCodes.Ldc_I4_M1;
66 opcodehash["ldc.i4.0"] = OpCodes.Ldc_I4_0;
67 opcodehash["ldc.i4.1"] = OpCodes.Ldc_I4_1;
68 opcodehash["ldc.i4.2"] = OpCodes.Ldc_I4_2;
69 opcodehash["ldc.i4.3"] = OpCodes.Ldc_I4_3;
70 opcodehash["ldc.i4.4"] = OpCodes.Ldc_I4_4;
71 opcodehash["ldc.i4.5"] = OpCodes.Ldc_I4_5;
72 opcodehash["ldc.i4.6"] = OpCodes.Ldc_I4_6;
73 opcodehash["ldc.i4.7"] = OpCodes.Ldc_I4_7;
74 opcodehash["ldc.i4.8"] = OpCodes.Ldc_I4_8;
77 public Exe(String name)
79 filename = name;
80 initOpcodeHash();
83 AssemblyName getAssemblyName(string s)
85 AssemblyName a = new AssemblyName();
86 a.Name = filename+"_assembly";
87 return a;
90 public void BeginModule(string ifile)
92 appdomain = System.Threading.Thread.GetDomain();
93 appname = getAssemblyName(filename);
94 appbuild = appdomain.DefineDynamicAssembly(appname,
95 AssemblyBuilderAccess.Save,
96 Io.genpath);
97 emodule = appbuild.DefineDynamicModule(
98 filename+"_module",
99 Io.GetOutputFilename(),
100 Io.gendebug);
101 Guid g = System.Guid.Empty;
102 if (Io.gendebug)
103 srcdoc = emodule.DefineDocument(ifile, g, g, g);
107 public void EndModule()
111 String s = Io.GetOutputFilename();
112 appbuild.Save(s);
113 Console.WriteLine("Saving assembly as "+s);
115 catch (Exception e)
117 Io.ICE(e.ToString());
121 public void BeginClass(String name, TypeAttributes access)
123 classname = name;
124 eclass = emodule.DefineType(name, access);
127 public void EndClass()
129 eclass.CreateType(); // create the class
133 * determine the IL static type
135 Type ilSType(bool sign, int type)
137 if (sign)
139 switch (type)
141 case Tok.T_CHAR: return Type.GetType("System.SByte");
142 case Tok.T_SHORT: return Type.GetType("System.Int16");
143 case Tok.T_DEFTYPE: return Type.GetType("System.Int32");
144 case Tok.T_INT: return Type.GetType("System.Int32");
145 case Tok.T_LONG: return Type.GetType("System.Int32");
146 case Tok.T_FLOAT: return Type.GetType("System.Single");
147 case Tok.T_DOUBLE: return Type.GetType("System.Double");
148 case Tok.T_VOID: return null;
149 default:
150 Io.ICE("Unhandled type " + type);
151 return null;
154 else
156 switch (type)
158 case Tok.T_CHAR: return Type.GetType("U1");
159 case Tok.T_SHORT: return Type.GetType("U2");
160 case Tok.T_DEFTYPE: return Type.GetType("U4");
161 case Tok.T_INT: return Type.GetType("U4");
162 case Tok.T_LONG: return Type.GetType("U4");
163 default:
164 Io.ICE("Unhandled type " + type);
165 return null;
171 * common routine to construct a signature string for a given varlist item
172 * requires a destination ptr, will return the updated dest ptr
174 private Type genDataTypeSig(Var e)
176 bool sign = true;
177 if (e == null)
178 return null;
180 if (e.getSign() == Tok.T_UNSIGNED) /* if var is unsigned, put it in sig */
181 sign = false;
183 Type sig = ilSType(sign, e.getTypeId()); /* get the datatype */
184 return (sig);
187 void genLoad(Var e)
189 int id = e.getClassId();
190 if (e == null)
191 Io.ICE("Load instruction with no variable ptr");
192 if (e.getLocalToken() != null)
194 // LocalToken lt = (LocalToken) e.getLocalToken();
195 LocalBuilder lt = (LocalBuilder) e.getLocalToken();
196 il.Emit(OpCodes.Ldloc, lt);
198 else if (e.getFieldBuilder() != null)
200 FieldBuilder fb = (FieldBuilder) e.getFieldBuilder();
201 if (id == Tok.T_STATIC)
202 il.Emit(OpCodes.Ldsfld, fb);
203 else
204 il.Emit(OpCodes.Ldfld, fb);
206 else
208 int index = e.getIndex();
209 if (id == Tok.T_PARAM)
211 if (index <= 256)
212 il.Emit(OpCodes.Ldarg_S, index);
213 else
214 il.Emit(OpCodes.Ldarg, index);
216 else if (id == Tok.T_AUTO || id == Tok.T_DEFCLASS)
218 if (index <= 256)
219 il.Emit(OpCodes.Ldloc_S, e.getIndex());
220 else
221 il.Emit(OpCodes.Ldloc, e.getIndex());
223 else
224 Io.ICE("Instruction load of unknown class ("
225 + e.getClassId()+")");
229 public void Load(IAsm a)
231 Var e = a.getVar();
232 genLoad(e);
235 public void Store(IAsm a)
237 Var e = a.getVar();
238 int id = e.getClassId();
239 if (e == null)
240 Io.ICE("Store instruction with no variable ptr");
241 if (e.getLocalToken() != null)
243 // LocalToken lt = (LocalToken) e.getLocalToken();
244 LocalBuilder lt = (LocalBuilder) e.getLocalToken();
245 il.Emit(OpCodes.Stloc, lt);
247 else if (e.getFieldBuilder() != null)
249 FieldBuilder fb = (FieldBuilder) e.getFieldBuilder();
250 if (id == Tok.T_STATIC)
251 il.Emit(OpCodes.Stsfld, fb);
252 else
253 il.Emit(OpCodes.Stfld, fb);
255 else
257 int index = e.getIndex();
258 if (id == Tok.T_PARAM)
260 if (index <= 256)
261 il.Emit(OpCodes.Starg_S, index);
262 else
263 il.Emit(OpCodes.Starg, index);
265 else if (id == Tok.T_AUTO || id == Tok.T_DEFCLASS)
266 il.Emit(OpCodes.Stloc, index);
267 else
268 Io.ICE("Instruction load of unknown class ("
269 + e.getClassId()+")");
273 public void FuncBegin(IAsm a)
275 Var func = a.getVar();
276 Type funcsig = genDataTypeSig(a.getVar()); /* gen return type info */
278 VarList paramlist = func.getParams(); /* get any params */
279 Type[] paramTypes = null; // in case no params
280 if (paramlist.Length() > 0)
282 int max = paramlist.Length();
283 paramTypes = new Type[max];
284 for (int i = 0; i < max; i++)
286 Var e = paramlist.FindByIndex(i);
287 paramTypes[i] = genDataTypeSig(e);
291 emethod = eclass.DefineMethod(func.getName(),
292 MethodAttributes.Static|MethodAttributes.Public,
293 funcsig, paramTypes);
294 func.setMethodBuilder(emethod); // save the method ref
297 * set the argument symbol info
299 for (int i = 0; i < paramlist.Length(); i++)
300 emethod.DefineParameter(i+1, 0, paramlist.FindByIndex(i).getName());
302 il = emethod.GetILGenerator(); // create new il generator
304 if (func.getName().Equals("main")) /* special entry point for main */
305 appbuild.SetEntryPoint(emethod);
306 // emodule.SetUserEntryPoint(emethod);
309 * must also re-init the label hashtable for each function
311 labelhash = new Hashtable();
313 localsdone = false;
316 public void Call(IAsm a)
318 Var func = a.getVar();
319 Object o = func.getMethodBuilder(); // get previous declared reference
320 if (o == null)
321 Io.ICE("No previous extern for (" + func.getName() + ")");
322 MethodBuilder mb = (MethodBuilder) o;
323 // il.Emit(OpCodes.Ldc_I4_0); // push 0 for the "this" ptr
324 // VarList x = func.getParams(); /* get any params */
325 // if (x.Length() > 0)
326 // {
327 // int max = x.Length();
328 // for (int i = 0; i < max; i++)
329 // {
330 // Var e = x.FindByIndex(i);
331 // genLoad(e);
332 // }
333 // }
334 il.Emit(OpCodes.Call, mb); // call the MethodBuilder
337 public void Insn(IAsm a)
339 Object o = opcodehash[a.getInsn()];
340 if (o == null)
341 Io.ICE("Instruction opcode (" + a.getInsn() + ") not found in hash");
342 il.Emit((OpCode) o);
345 private Hashtable labelhash; /* labelname hashtable */
347 * get and/or create IL label
348 * put it in hash for reuse
350 private Object getILLabel(IAsm a)
352 String s = a.getLabel();
353 Object l = labelhash[s];
354 if (l == null)
356 l = (Object) il.DefineLabel();
357 labelhash[s] = l;
359 return l;
362 public void Label(IAsm a)
364 il.MarkLabel((Label) getILLabel(a));
367 public void Branch(IAsm a)
369 Object o = opcodehash[a.getInsn()];
370 if (o == null)
371 Io.ICE("Instruction branch opcode (" + a.getInsn() + ") not found in hash");
372 il.Emit((OpCode) o, (Label) getILLabel(a));
375 public void Ret(IAsm a)
377 il.Emit(OpCodes.Ret);
380 public void FuncEnd()
383 * fill in the current IL stream for this method
385 // emethod.CreateMethodBody(il);
386 il = null;
387 localsdone = false;
390 public void LocalVars(VarList v)
392 int max = v.Length();
394 for (int i = 0; i < max; i++) // loop thru the local params
396 Var e = v.FindByIndex(i); // indexed by number
397 Type et = genDataTypeSig(e);
398 // LocalToken t = emethod.DeclareLocal(et);
399 LocalBuilder t = il.DeclareLocal(et);
400 if (Io.gendebug)
401 t.SetLocalSymInfo(e.getName());
402 e.setLocalToken(t);
404 localsdone = true;
407 public void FieldDef(IAsm a)
409 Var e = a.getVar(); /* get the field var ptr */
410 FieldAttributes attr = FieldAttributes.Private; /* default attributes is private */
412 if (e.getClassId() == Tok.T_STATIC)
413 attr |= FieldAttributes.Static;
415 Type t = genDataTypeSig(e); /* gen type info */
417 FieldBuilder f = eclass.DefineField(e.getName(), t, attr); // returns token
418 e.setFieldBuilder((Object) f); // store token for later usage
421 public void LoadConst(IAsm a)
423 int value = Convert.ToInt32(a.getInsn());
425 if (value > 127 || value < -128) /* if must use long form */
427 il.Emit(OpCodes.Ldc_I4, value);
429 else if (value > 8 || value < -1) /* if must use medium form */
431 il.Emit(OpCodes.Ldc_I4_S, value);
433 else if (value == -1)
435 il.Emit(OpCodes.Ldc_I4_M1);
437 else /* else use short form */
439 Object o = opcodehash["ldc.i4."+a.getInsn()];
440 if (o == null)
441 Io.ICE("Could not find opcode for (Ldc_I4_" + a.getInsn() + ")");
442 il.Emit((OpCode) o);
446 public void Comment(IAsm a)
448 if (Io.gendebug)
450 if (localsdone)
452 if (a != null && il != null)
454 if (!IsNextNonInsnGen(a))
457 // Console.WriteLine("Line ("+a.getCommentLine().ToString()+")="+a.getComment());
458 int l = a.getCommentLine();
459 il.MarkSequencePoint(srcdoc, l, 0, l, 0);
467 * is the next assembler directive an non-instruction generation
469 * this is used to keep marksequencepoint from getting multiple calls
470 * with no intervening instructions, which causes it to work incorrectly
472 private bool IsNextNonInsnGen(IAsm a)
474 IAsm cur = a.getNext();
475 if (cur == null)
476 return true;
477 int type = cur.getIType();
480 * skip intervening labels
482 while (type == IAsm.I_LABEL)
484 cur = cur.getNext();
485 type = cur.getIType();
489 * if next is comment then return true
491 if (type == IAsm.I_COMMENT)
492 return true;
493 return false;